package tcp

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
	"log"
	"net"
)

const HEAD_LEN int = 4
const HEAD_LEN_INT32 = int32(HEAD_LEN)

//StartTcpServerWithThread 固定长度的解析TCP包
// 这个版本是阻塞版本，这里采用的策略是使用多线程处理，来一个TCP连接的请求，
// 就启动一个线程来处理这个连接的请求。并不是最优的选择，会存在C10K问题。
func StartTcpServerWithThread(handle func([]byte), ip string, port int) {
	ipPort := fmt.Sprintf("%s:%d", ip, port)
	log.Printf("start tcp server ip:port %v \n", ipPort)
	listen, err := net.Listen("tcp", ipPort)
	if err != nil {
		fmt.Println("listen failed, err:", err)
		return
	}
	defer listen.Close()
	log.Printf("start tcp server success")
	for {
		conn, err := listen.Accept() // 建立连接
		if err != nil {
			log.Println("accept failed, err:", err)
			continue
		}
		go handleConn(conn, handle)
	}
}

func handleConn(conn net.Conn, handle func([]byte)) {

	log.Printf("tcp server new thread started ............")
	defer conn.Close()
	reader := bufio.NewReader(conn)
	for {
		//先读取4个字节，表示长度 Peek表示只读取，而不从流里实际拿出来。
		//有错误也正常，表示没拿到4个长度
		peek, err := reader.Peek(HEAD_LEN)

		if err != nil {
			// EOF就表示终止了，没必要继续读了
			if err == io.EOF {
				break
			} else {
				log.Println("tcp server read head error：", err)
			}
		}
		//这里需要把4个字节的数组，转换为实际的长度
		buffer := bytes.NewBuffer(peek)
		var length int32
		//读到4个字节的长度了，存到length
		err = binary.Read(buffer, binary.BigEndian, &length)
		if err != nil {
			if err == io.EOF {
				log.Println("tcp server read head error：", err)
				break
			}
			log.Println("tcp server read head len error：", err)
		}
		if int32(reader.Buffered()) < length+HEAD_LEN_INT32 {
			log.Println("tcp server length:", length, " buffered: ", int32(reader.Buffered()))
			continue
		}
		data := make([]byte, length+HEAD_LEN_INT32)
		_, err = reader.Read(data)
		if err != nil {
			continue
		}
		//获取到TCP的数据了，交给用户自定义的函数处理数据。
		handle(data[HEAD_LEN_INT32:])
	}
}
